﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using InterLinq.Base;
using InterLinq.Client;
using InterLinq.Objects;
using InterLinq.Test.PD;
using InterLinq.UnitTests.Artefacts.Objects;
using InterLinq.Views;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sebarf.Core;
using Sebarf.Core.Interfaces;
using Sebarf.Server;

namespace InterLinq.UnitTests.Objects {
	/// <summary>
	/// Tests with the domain model of a <see cref="Company"/> with <see cref="Department">Departments</see>
	/// and <see cref="Employee"/>.
	/// </summary>
	[TestClass]
	public class CompanyExampleTest {
		#region Fields

		/// <summary>
		/// Context instance providing <see cref="IQueryable">IQueryables</see>.
		/// </summary>
		protected CompanyContext m_companyExampleContext;

		#endregion

		#region Properties

		/// <summary>
		///Gets or sets the test context which provides
		///information about and functionality for the current test run.
		///</summary>
		public TestContext TestContext { get; set; }

		#endregion

		#region Count/Sum/Min/Max/Avg Tests

		/// <summary>
		/// Simply count all employees.
		/// </summary>
		[TestMethod]
		[Description("Simply count all employees.")]
		public void Count_01_Employees() {
			int numberOfEmployees = m_companyExampleContext.Employees.Count();
			Assert.AreEqual(13, numberOfEmployees);
		}

		/// <summary>
		/// Gets the number of female employees.
		/// </summary>
		[TestMethod]
		[Description("Gets the number of female employees.")]
		public void Count_02_FemaleEmployees() {
			int numberOfFemaleEmployees = m_companyExampleContext.Employees.Count(emp => !(emp.IsMale));
			Assert.AreEqual(6, numberOfFemaleEmployees);
		}

		/// <summary>
		/// Sums all salaries after a selection.
		/// </summary>
		[TestMethod]
		[Description("Sums all salaries after a selection.")]
		public void Sum_01_AllSalaries() {
			double totalSalary = m_companyExampleContext.Employees.Select(emp => emp.Salary).Sum();
			Assert.AreEqual(96000d, totalSalary);
		}

		/// <summary>
		/// Gets the minimum Grade.
		/// </summary>
		[TestMethod]
		[Description("Gets the minimum Grade.")]
		public void Min_01_Grade() {
			double minGrade = m_companyExampleContext.Employees.Select(emp => emp.Grade).Min();
			Assert.AreEqual(1, minGrade);
		}

		/// <summary>
		/// Selects the Departments and their employee with the lowest salary.
		/// </summary>
		[TestMethod]
		[Description("Selects the Departments and their employee with the lowest salary.")]
		public void Min_02_SalaryInDepartment() {
			IEnumerable<GenericView> minSalaryQuery = from e in m_companyExampleContext.Employees.ToArray()
													  group e by e.Department
														  into g
														  select
														  new GenericView("Department", g.Key, "MinSalary", g.Min(e => e.Salary),
																		   "LowestSalaryEmployee",
																		   (from empInGroup in g
																			where empInGroup.Salary == g.Min(e => e.Salary)
																			select empInGroup).ToArray());

			GenericView[] foundMinSalaries = minSalaryQuery.ToArray();
			foreach (GenericView minSalaryEntry in foundMinSalaries) {
				// When the CEO is found
				if (minSalaryEntry.GetValue<Department>("Department") == null) {
					Assert.AreEqual(1, minSalaryEntry.GetValue<IEnumerable<Employee>>("LowestSalaryEmployee").Count());
					Assert.AreEqual(20000d, minSalaryEntry.GetValue<IEnumerable<Employee>>("LowestSalaryEmployee").First().Salary);
				}
				// When the "Instant-Guezli Research" is found
				else if (minSalaryEntry.GetValue<Department>("Department").Name == "Instant-Guezli Research") {
					Assert.AreEqual(1, minSalaryEntry.GetValue<IEnumerable<Employee>>("LowestSalaryEmployee").Count());
					Assert.AreEqual(4000d, minSalaryEntry.GetValue<IEnumerable<Employee>>("LowestSalaryEmployee").First().Salary);
				}
				// When the "Instant-Guezli Production" is found
				else if (minSalaryEntry.GetValue<Department>("Department").Name == "Instant-Guezli Production") {
					Assert.AreEqual(1, minSalaryEntry.GetValue<IEnumerable<Employee>>("LowestSalaryEmployee").Count());
					Assert.AreEqual(3000d, minSalaryEntry.GetValue<IEnumerable<Employee>>("LowestSalaryEmployee").First().Salary);
				}
				// When the "Instant-Guezli Import" is found
				else if (minSalaryEntry.GetValue<Department>("Department").Name == "Instant-Guezli Import") {
					Assert.AreEqual(1, minSalaryEntry.GetValue<IEnumerable<Employee>>("LowestSalaryEmployee").Count());
					Assert.AreEqual(3500d, minSalaryEntry.GetValue<IEnumerable<Employee>>("LowestSalaryEmployee").First().Salary);
				}
				else {
					Assert.Fail("A unknown department has been found.");
				}
			}
		}

		/// <summary>
		/// Select the highest foundation date.
		/// </summary>
		[TestMethod]
		[Description("Select the highest foundation date.")]
		public void Max_01_Foundation() {
			DateTime maxFoundationQuery = m_companyExampleContext.Departments.Select(fd => fd.Foundation).Max();
			Assert.AreEqual(new DateTime(1980, 5, 5), maxFoundationQuery);
		}

		/// <summary>
		/// Select the highest quality level.
		/// </summary>
		[TestMethod]
		[Description("Select the highest quality level.")]
		public void Max_02_QualityLevel() {
			int maxQualityLevel = m_companyExampleContext.Departments.Max(d => d.QualityLevel);
			Assert.AreEqual(8, maxQualityLevel);
		}

		/// <summary>
		/// Gets the average Grade of all employees.
		/// </summary>
		[TestMethod]
		[Description("Gets the average Grade of all employees.")]
		public void Avg_01_Grade() {
			double avgGrade = m_companyExampleContext.Employees.Average(e => e.Grade);
			Assert.AreEqual(6.0769d, Math.Round(avgGrade, 4));
		}

		#endregion

		#region Join

		/// <summary>
		/// Use foreign key navigation to select all employees of a department.
		/// </summary>
		[TestMethod]
		[Description("Use foreign key navigation to select all employees of a department.")]
		public void Join_01_SimpleJoin() {
			IEnumerable<Employee> query = from dep in m_companyExampleContext.Departments.ToArray()
										  from emp in dep.Employees
										  where dep.Name == "Instant-Guezli Research"
										  select emp;
			Employee[] foundEmployees = query.ToArray();
			Assert.AreEqual(3, foundEmployees.Length);
		}

		/// <summary>
		/// Use foreign key navigation to select all departments whose manager is female.
		/// </summary>
		[TestMethod]
		[Description("Use foreign key navigation to select all departments whose manager is female.")]
		public void Join_02_FKNavigation() {
			IQueryable<Department> femManagedDepQuery = from dep in m_companyExampleContext.Departments
														where !dep.Manager.IsMale
														select dep;
			Department[] foundFManagedDep = femManagedDepQuery.ToArray();
			Assert.AreEqual(1, foundFManagedDep.Length);
			Assert.IsFalse(foundFManagedDep[0].Manager.IsMale,
							"The Manager of the found department is male but should be female.");
		}

		#endregion

		#region OrderBy

		/// <summary>
		/// Simply order all employees by their salary.
		/// </summary>
		[TestMethod]
		[Description("Simply order all employees by their salary.")]
		public void OrderBy_01_Simple() {
			IOrderedQueryable<Employee> employeeQuery = from emp in m_companyExampleContext.Employees
														orderby emp.Salary
														select emp;
			Employee[] foundEmployees = employeeQuery.ToArray();
			Assert.AreEqual(13, foundEmployees.Length);
			Employee lastEmployee = null;
			foreach (Employee emp in foundEmployees) {
				if (lastEmployee != null) {
					Assert.IsTrue(lastEmployee.Salary <= emp.Salary, "Last employees salary was higher but shoudn't.");
				}
				lastEmployee = emp;
			}
		}

		/// <summary>
		/// Simply order all employees by their salary descending.
		/// </summary>
		[TestMethod]
		[Description("Simply order all employees by their salary descending.")]
		public void OrderBy_02_Descending() {
			IOrderedQueryable<Employee> employeeQuery = from emp in m_companyExampleContext.Employees
														orderby emp.Salary descending
														select emp;
			Employee[] foundEmployees = employeeQuery.ToArray();
			Assert.AreEqual(13, foundEmployees.Length);
			Employee lastEmployee = null;
			foreach (Employee emp in foundEmployees) {
				if (lastEmployee != null) {
					Assert.IsTrue(lastEmployee.Salary >= emp.Salary, "Last employees salary was lower but shoudn't.");
				}
				lastEmployee = emp;
			}
		}

		#endregion

		#region GroupBy

		/// <summary>
		/// Use group by and max to get the maximum salary for each department.
		/// </summary>
		[TestMethod]
		[Description("Use group by and max to get the maximum salary for each department.")]
		public void GroupBy_01_MaxSalary() {
			IQueryable<GenericView> maxSalaryQuery = from emp in m_companyExampleContext.Employees
													 group emp by emp.Department
														 into g
														 select
														 new GenericView().AddEntryToView("Department", g.Key).AddEntryToView(
														 "MaxSalary", g.Max(e => e.Salary));

			GenericView[] maxSalaries = maxSalaryQuery.ToArray();
			Assert.AreEqual(4, maxSalaries.Length);
			foreach (GenericView maxSalary in maxSalaries) {
				// When the CEO is found
				if (maxSalary.GetValue<Department>("Department") == null) {
					Assert.AreEqual(20000d, maxSalary.GetValue<Double>("MaxSalary"));
				}
				// When the "Instant-Guezli Research" is found
				else if (maxSalary.GetValue<Department>("Department").Name == "Instant-Guezli Research") {
					Assert.AreEqual(10000d, maxSalary.GetValue<Double>("MaxSalary"));
				}
				// When the "Instant-Guezli Production" is found
				else if (maxSalary.GetValue<Department>("Department").Name == "Instant-Guezli Production") {
					Assert.AreEqual(11000d, maxSalary.GetValue<Double>("MaxSalary"));
				}
				// When the "Instant-Guezli Import" is found
				else if (maxSalary.GetValue<Department>("Department").Name == "Instant-Guezli Import") {
					Assert.AreEqual(12000d, maxSalary.GetValue<Double>("MaxSalary"));
				}
				else {
					Assert.Fail("A unknown department has been found.");
				}
			}
		}

		/// <summary>
		/// Use group by to find the department with more then 25000 total salary.
		/// </summary>
		[TestMethod]
		[Description("Use group by to find the department with more then 25000 total salary.")]
		public void GroupBy_02_Having() {
			IQueryable<GenericView> salaryQuery = from emp in m_companyExampleContext.Employees
												  group emp by emp.Department
													  into g
													  where g.Key != null
													  where g.Sum(emp => emp.Salary) > 25000
													  select
													  new GenericView().AddEntryToView("DepartmentName", g.Key.Name).
													  AddEntryToView("MaxSalary", g.Sum(emp => emp.Salary));
			GenericView[] maxSalaries = salaryQuery.ToArray();
			Assert.AreEqual(1, maxSalaries.Length);
			Assert.AreEqual("Instant-Guezli Production", maxSalaries[0].GetValue<String>("DepartmentName"));
			Assert.AreEqual(26000d, maxSalaries[0].GetValue<Double>("MaxSalary"));
		}

		/// <summary>
		/// Use group by to group employees by department and sex.
		/// </summary>
		[TestMethod]
		[Description("Use group by to group employees by department and sex.")]
		public void GroupBy_03_DoubleGroup() {
			IEnumerable<GenericView> query = from emp in m_companyExampleContext.Employees.ToArray()
											 group emp by new { emp.Department, emp.IsMale }
												 into g
												 select new GenericView().AddEntryToView("Key", g.Key);

			GenericView[] results = query.ToArray();
			Assert.AreEqual(7, results.Length);
		}

		#endregion

		#region Where

		/// <summary>
		/// Finds all Employees by a name.
		/// </summary>
		[TestMethod]
		[Description("Finds all Employees by a name.")]
		public void Where_01_EmployeeByName() {
			string name = "Sio Wernli";
			IQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees where e.Name == name select e;

			Employee[] foundEmployees = employeesQuery.ToArray();

			Assert.AreEqual(1, foundEmployees.Length);
			Assert.AreEqual(name, foundEmployees[0].Name);
		}

		/// <summary>
		/// Finds all Employees by a Department name.
		/// </summary>
		[TestMethod]
		[Description("Finds all Employees by a Department name.")]
		public void Where_03_DepartmentByFoundation() {
			IQueryable<Department> departmentsQuery = from d in m_companyExampleContext.Departments
													  where d.Foundation >= new DateTime(1910, 1, 1)
													  select d;

			Department[] foundDepartments = departmentsQuery.ToArray();

			Assert.AreEqual(2, foundDepartments.Length);
			Assert.AreEqual("Instant-Guezli Research", foundDepartments[0].Name);
			Assert.AreEqual("Instant-Guezli Import", foundDepartments[1].Name);
		}

		/// <summary>
		/// Finds all male Employees with a low grade (less or equal than 5).
		/// </summary>
		[TestMethod]
		[Description("Finds all male Employees with a low grade (less or equal than 5).")]
		public void Where_04_MaleWithLowGrade() {
			IQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees
												  where e.IsMale && e.Grade <= 5
												  select e;

			Employee[] foundEmployees = employeesQuery.ToArray();

			Assert.AreEqual(3, foundEmployees.Length);
			Assert.AreEqual("Harry Bo", foundEmployees[0].Name);
			Assert.AreEqual("Rainer Zufall", foundEmployees[1].Name);
			Assert.AreEqual("Lee Mone", foundEmployees[2].Name);
		}

		/// <summary>
		/// Finds all female Employees with best grade (greater or equal than 10).
		/// </summary>
		[TestMethod]
		[Description("Finds all female Employees with best grade (greater or equal than 10).")]
		public void Where_05_FemalePlusBestGradedMale() {
			IQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees
												  where !e.IsMale || e.Grade >= 10
												  select e;

			Employee[] foundEmployees = employeesQuery.ToArray();

			Assert.AreEqual(8, foundEmployees.Length);
			Assert.AreEqual("Sio Wernli", foundEmployees[0].Name);
			Assert.AreEqual("Stephanie Süss", foundEmployees[1].Name);
			Assert.AreEqual("Manuela Zucker", foundEmployees[2].Name);
			Assert.AreEqual("Prof. Joe Kolade", foundEmployees[3].Name);
			Assert.AreEqual("Clara Vorteil", foundEmployees[4].Name);
			Assert.AreEqual("Anna Nass", foundEmployees[5].Name);
			Assert.AreEqual("Franziska Ner", foundEmployees[6].Name);
			Assert.AreEqual("Gertraut Sichnicht", foundEmployees[7].Name);
		}

		/// <summary>
		/// Finds best grade male (greater or equal than 10).
		/// </summary>
		[TestMethod]
		[Description("Finds best grade male (greater or equal than 10).")]
		public void Where_06_BestGradedMale() {
			IQueryable<Employee> employeesQuery =
				m_companyExampleContext.Employees.Where(e => e.IsMale).Where(e => e.Grade >= 10);

			Employee[] foundEmployees = employeesQuery.ToArray();

			Assert.AreEqual(2, foundEmployees.Length);
			Assert.AreEqual("Sio Wernli", foundEmployees[0].Name);
			Assert.AreEqual("Prof. Joe Kolade", foundEmployees[1].Name);
		}

		/// <summary>
		/// Finds the first employee.
		/// </summary>
		[TestMethod]
		[Description("Finds the first employee.")]
		public void Where_07_FirstEmployee() {
			Employee foundEmployee = m_companyExampleContext.Employees.First();
			Assert.AreEqual("Sio Wernli", foundEmployee.Name);
		}

		/// <summary>
		/// Finds the first best graded employee.
		/// </summary>
		[TestMethod]
		[Description("Finds the first best graded employee.")]
		public void Where_08_FirstBestGradedEmployee() {
			Employee foundEmployee = m_companyExampleContext.Employees.First(e => e.Grade >= 10);
			Assert.AreEqual("Sio Wernli", foundEmployee.Name);
		}

		#endregion

		#region Union / Concat / Intersect / Except

		/// <summary>
		/// Concats Name and Salary of all Employees with all Department names.
		/// </summary>
		[TestMethod]
		[Description("Concats Name and Salary of all Employees with all Department names.")]
		public void Concat_01() {
			IQueryable<string> concatenationQuery =
				(from e in m_companyExampleContext.Employees select e.Name).Concat(from e in m_companyExampleContext.Employees
																				   select e.Salary.ToString()).Concat(
					from d in m_companyExampleContext.Departments select d.Name);

			string[] foundConcatenations = concatenationQuery.ToArray();

			Assert.AreEqual(29, foundConcatenations.Length);
		}

		/// <summary>
		/// Concats Name / Grade of all Employees with all Department Name / QualityLevel.
		/// </summary>
		[TestMethod]
		[Description("Concats Name / Grade of all Employees with all Department Name / QualityLevel.")]
		public void Concat_02() {
			IEnumerable<GenericView> concatenationQuery =
				(from e in m_companyExampleContext.Employees select new GenericView(new InternalData(e, new[] { "Name", "Grade" })))
					.ToArray().Concat((from d in m_companyExampleContext.Departments
									   select new GenericView(new InternalData(d, new[] { "Name", "QualityLevel as Grade" }))).
											ToArray());

			GenericView[] foundConcatenations = concatenationQuery.ToArray();

			Assert.AreEqual(16, foundConcatenations.Length);
		}

		/// <summary>
		/// Unions the Grade of all Employees with all Department QualityLevels.
		/// Union removes duplicated values (Distinct).
		/// </summary>
		[TestMethod]
		[Description(
			"Unions the Grade of all Employees with all Department QualityLevels. " +
			"Union removes duplicated values (Distinct).")]
		public void Union_01() {
			IQueryable<int> unionQuery =
				(from e in m_companyExampleContext.Employees select e.Grade).Union(from d in m_companyExampleContext.Departments
																				   select d.QualityLevel);

			int[] foundUnions = unionQuery.ToArray();

			Assert.AreEqual(10, foundUnions.Length);
		}

		/// <summary>
		/// Intersects the Grade of all Employees with all Department QualityLevels.
		/// </summary>
		[TestMethod]
		[Description("Intersects the Grade of all Employees with all Department QualityLevels.")]
		public void Intersect_01() {
			IQueryable<int> intersectQuery =
				(from e in m_companyExampleContext.Employees select e.Grade).Intersect(
					from d in m_companyExampleContext.Departments select d.QualityLevel);

			int[] foundIntersect = intersectQuery.ToArray();

			Assert.AreEqual(2, foundIntersect.Length);
		}

		/// <summary>
		/// Excepts the Grade of all Employees with all Department QualityLevels.
		/// </summary>
		[TestMethod]
		[Description("Excepts the Grade of all Employees with all Department QualityLevels.")]
		public void Except_01() {
			IQueryable<int> intersectQuery =
				(from e in m_companyExampleContext.Employees select e.Grade).Except(from d in m_companyExampleContext.Departments
																					select d.QualityLevel);

			int[] foundIntersect = intersectQuery.ToArray();

			Assert.AreEqual(7, foundIntersect.Length);
		}

		/// <summary>
		/// Excepts the Grade of all Employees with all Department QualityLevels.
		/// </summary>
		[TestMethod]
		[Description("Excepts the Grade of all Employees with all Department QualityLevels.")]
		public void Distinct_01() {
			IQueryable<string> employeeQuery = from e in m_companyExampleContext.Employees
											   where e.Department != null
											   select e.Department.Name;

			IQueryable<string> employeeDistinctQuery = employeeQuery.Distinct();
			string[] foundEmployees = employeeDistinctQuery.ToArray();

			Assert.AreEqual(3, foundEmployees.Length);
			Assert.AreEqual("Instant-Guezli Research", foundEmployees[0]);
			Assert.AreEqual("Instant-Guezli Production", foundEmployees[1]);
			Assert.AreEqual("Instant-Guezli Import", foundEmployees[2]);
		}

		#endregion

		#region Skip / Take

		/// <summary>
		/// Selects all Employees. The first 10 results will be skipped.
		/// </summary>
		[TestMethod]
		[Description("Selects all Employees. The first 10 results will be skipped.")]
		public void Skip_01() {
			IOrderedQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees
														 orderby e.Id ascending
														 select e;

			Employee[] foundEmployees = employeesQuery.Skip(10).ToArray();

			Assert.AreEqual(3, foundEmployees.Length);
			Assert.AreEqual("Lee Mone", foundEmployees[0].Name);
			Assert.AreEqual("Franziska Ner", foundEmployees[1].Name);
			Assert.AreEqual("Gertraut Sichnicht", foundEmployees[2].Name);
		}

		/// <summary>
		/// Selects all Employees descending. The first 10 results will be skipped.
		/// </summary>
		[TestMethod]
		[Description("Selects all Employees descending. The first 10 results will be skipped.")]
		public void Skip_02() {
			IOrderedQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees
														 orderby e.Id descending
														 select e;

			Employee[] foundEmployees = employeesQuery.Skip(10).ToArray();

			Assert.AreEqual(3, foundEmployees.Length);
			Assert.AreEqual("Stephanie Süss", foundEmployees[0].Name);
			Assert.AreEqual("Dr. Rainer Hohn", foundEmployees[1].Name);
			Assert.AreEqual("Sio Wernli", foundEmployees[2].Name);
		}

		/// <summary>
		/// The same test as Skip_02, but the return value of skip is saved in a separate variable.
		/// </summary>
		[TestMethod]
		[Description("The same test as Skip_02, but the return value of skip is saved in a separate variable.")]
		public void Skip_03() {
			IOrderedQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees
														 orderby e.Id descending
														 select e;

			IQueryable<Employee> employeesSkipQuery = employeesQuery.Skip(10);
			Employee[] foundEmployees = employeesSkipQuery.ToArray();

			Assert.AreEqual(3, foundEmployees.Length);
			Assert.AreEqual("Stephanie Süss", foundEmployees[0].Name);
			Assert.AreEqual("Dr. Rainer Hohn", foundEmployees[1].Name);
			Assert.AreEqual("Sio Wernli", foundEmployees[2].Name);
		}

		/// <summary>
		/// Selects first 3 Employees.
		/// </summary>
		[TestMethod]
		[Description("Selects first 3 Employees.")]
		public void Take_01() {
			IOrderedQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees
														 orderby e.Id ascending
														 select e;

			Employee[] foundEmployees = employeesQuery.Take(3).ToArray();

			Assert.AreEqual(3, foundEmployees.Length);
			Assert.AreEqual("Sio Wernli", foundEmployees[0].Name);
			Assert.AreEqual("Dr. Rainer Hohn", foundEmployees[1].Name);
			Assert.AreEqual("Stephanie Süss", foundEmployees[2].Name);
		}

		/// <summary>
		/// Selects last 3 Employees.
		/// </summary>
		[TestMethod]
		[Description("Selects last 3 Employees.")]
		public void Take_02() {
			IOrderedQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees
														 orderby e.Id descending
														 select e;

			Employee[] foundEmployees = employeesQuery.Take(3).ToArray();

			Assert.AreEqual(3, foundEmployees.Length);
			Assert.AreEqual("Gertraut Sichnicht", foundEmployees[0].Name);
			Assert.AreEqual("Franziska Ner", foundEmployees[1].Name);
			Assert.AreEqual("Lee Mone", foundEmployees[2].Name);
		}

		/// <summary>
		/// Selects first 3 Employees after skipping 3 elements.
		/// </summary>
		[TestMethod]
		[Description("Selects first 3 Employees after skipping 3 elements.")]
		public void SkipTake_01() {
			IOrderedQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees
														 orderby e.Id ascending
														 select e;

			Employee[] foundEmployees = employeesQuery.Skip(3).Take(3).ToArray();

			Assert.AreEqual(3, foundEmployees.Length);
			Assert.AreEqual("Manuela Zucker", foundEmployees[0].Name);
			Assert.AreEqual("Harry Bo", foundEmployees[1].Name);
			Assert.AreEqual("Prof. Joe Kolade", foundEmployees[2].Name);
		}

		/// <summary>
		/// Selects first 3 Employees after skipping 3 elements descending.
		/// </summary>
		[TestMethod]
		[Description("Selects first 3 Employees after skipping 3 elements descending.")]
		public void SkipTake_02() {
			IOrderedQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees
														 orderby e.Id descending
														 select e;

			Employee[] foundEmployees = employeesQuery.Skip(3).Take(3).ToArray();

			Assert.AreEqual(3, foundEmployees.Length);
			Assert.AreEqual("Anna Nass", foundEmployees[0].Name);
			Assert.AreEqual("Johannes Beer", foundEmployees[1].Name);
			Assert.AreEqual("Clara Vorteil", foundEmployees[2].Name);
		}

		#endregion

		#region Null

		/// <summary>
		/// Selects all Employees with no department.
		/// </summary>
		[TestMethod]
		[Description("Selects all Employees with no department.")]
		public void Null_01() {
			IQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees where e.Department == null select e;

			Employee[] foundEmployees = employeesQuery.ToArray();

			Assert.AreEqual(1, foundEmployees.Length);
			Assert.AreEqual("Sio Wernli", foundEmployees[0].Name);
		}

		#endregion

		#region String / Data Functions

		/// <summary>
		/// This sample uses the + operator to concatenate string fields.
		/// </summary>
		[TestMethod]
		[Description("This sample uses the + operator to concatenate string fields.")]
		public void String_01_PlusOperator() {
			IQueryable<string> employeesQuery = from e in m_companyExampleContext.Employees
												select "Name: " + e.Name + ", " + "Grade: " + e.Grade;

			string[] foundEmployees = employeesQuery.ToArray();

			Assert.AreEqual(13, foundEmployees.Length);
			Assert.AreEqual("Name: Sio Wernli, Grade: 10", foundEmployees[0]);
		}

		/// <summary>
		/// This sample uses the Length property to find all Employees whose
		/// name is longer than 15 characters.
		/// </summary>
		[TestMethod]
		[Description(
			"This sample uses the Length property to find all Employees whose " + "name is longer than 15 characters.")]
		public void String_02_Length() {
			IQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees where e.Name.Length > 15 select e;

			Employee[] foundEmployees = employeesQuery.ToArray();

			Assert.AreEqual(2, foundEmployees.Length);
			Assert.AreEqual("Prof. Joe Kolade", foundEmployees[0].Name);
			Assert.AreEqual("Gertraut Sichnicht", foundEmployees[1].Name);
		}

		/// <summary>
		/// This sample uses the Contains method to find all Employees whose
		/// Name contains '.'
		/// </summary>
		[TestMethod]
		[Description("This sample uses the Contains method to find all Employees whose " + "Name contains '.'")]
		public void String_03_Contains() {
			IQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees
												  where e.Name.Contains(".")
												  select e;

			Employee[] foundEmployees = employeesQuery.ToArray();

			Assert.AreEqual(2, foundEmployees.Length);
			Assert.AreEqual("Dr. Rainer Hohn", foundEmployees[0].Name);
			Assert.AreEqual("Prof. Joe Kolade", foundEmployees[1].Name);
		}

		/// <summary>
		/// This sample uses the IndexOf method to find the first instance of
		/// a space in each Employees contact name.
		/// </summary>
		[TestMethod]
		[Description(
			"This sample uses the IndexOf method to find the first instance of " + "a space in each Employees contact name.")]
		public void String_04_IndexOf() {
			IQueryable<GenericView> employeesQuery = from e in m_companyExampleContext.Employees
													 select
														new GenericView().AddEntryToView("Name", e.Name).AddEntryToView(
														"FirstSpaceIndex", e.Name.IndexOf(" "));

			GenericView[] foundEmployees = employeesQuery.ToArray();

			Assert.AreEqual(13, foundEmployees.Length);
			Assert.AreEqual("Sio Wernli", foundEmployees[0].GetValue<String>("Name"));
			Assert.AreEqual(3, foundEmployees[0].GetValue<int>("FirstSpaceIndex"));
			Assert.AreEqual("Dr. Rainer Hohn", foundEmployees[1].GetValue<String>("Name"));
			Assert.AreEqual(3, foundEmployees[1].GetValue<int>("FirstSpaceIndex"));
			Assert.AreEqual("Stephanie Süss", foundEmployees[2].GetValue<String>("Name"));
			Assert.AreEqual(9, foundEmployees[2].GetValue<int>("FirstSpaceIndex"));
		}

		/// <summary>
		/// This sample uses the StartsWith method to find Employees whose
		/// name starts with 'S'.
		/// </summary>
		[TestMethod]
		[Description("This sample uses the StartsWith method to find Employees whose " + "name starts with 'S'.")]
		public void String_05_StartsWith() {
			IQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees
												  where e.Name.StartsWith("S")
												  select e;

			Employee[] foundEmployees = employeesQuery.ToArray();

			Assert.AreEqual(2, foundEmployees.Length);
			Assert.AreEqual("Sio Wernli", foundEmployees[0].Name);
			Assert.AreEqual("Stephanie Süss", foundEmployees[1].Name);
		}

		/// <summary>
		/// This sample uses the EndsWith method to find Employees whose
		/// name ends with 'l'.
		/// </summary>
		[TestMethod]
		[Description("This sample uses the EndsWith method to find Employees whose " + "name ends with 'l'.")]
		public void String_06_EndsWith() {
			IQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees
												  where e.Name.EndsWith("l")
												  select e;

			Employee[] foundEmployees = employeesQuery.ToArray();

			Assert.AreEqual(2, foundEmployees.Length);
			Assert.AreEqual("Rainer Zufall", foundEmployees[0].Name);
			Assert.AreEqual("Clara Vorteil", foundEmployees[1].Name);
		}

		/// <summary>
		/// This sample uses the Substring method to return Employee names starting
		/// from the fifth letter.
		/// </summary>
		[TestMethod]
		[Description("This sample uses the Substring method to return Employee names starting " + "from the fifth letter.")]
		public void String_07_Substring() {
			IQueryable<string> employeesQuery = from e in m_companyExampleContext.Employees select e.Name.Substring(4);

			string[] foundEmployees = employeesQuery.ToArray();

			Assert.AreEqual(13, foundEmployees.Length);
			Assert.AreEqual("Wernli", foundEmployees[0]);
			Assert.AreEqual("Rainer Hohn", foundEmployees[1]);
		}

		/// <summary>
		/// This sample uses the ToUpper / ToLower method to return Employee names
		/// that have been converted to uppercase / lowercase.
		/// </summary>
		[TestMethod]
		[Description(
			"This sample uses the ToUpper / ToLower method to return Employee names " +
			"that have been converted to uppercase / lowercase.")]
		public void String_08_ToUpperToLower() {
			IQueryable<GenericView> employeesQuery = from e in m_companyExampleContext.Employees
													 select
														new GenericView().AddEntryToView("Name", e.Name).AddEntryToView(
														"NameUpper", e.Name.ToUpper()).AddEntryToView("NameLower",
																										e.Name.ToLower());

			GenericView[] foundEmployees = employeesQuery.ToArray();

			Assert.AreEqual(13, foundEmployees.Length);
			Assert.AreEqual("Sio Wernli", foundEmployees[0].GetValue<String>("Name"));
			Assert.AreEqual("SIO WERNLI", foundEmployees[0].GetValue<String>("NameUpper"));
			Assert.AreEqual("sio wernli", foundEmployees[0].GetValue<String>("NameLower"));
			Assert.AreEqual("Dr. Rainer Hohn", foundEmployees[1].GetValue<String>("Name"));
			Assert.AreEqual("DR. RAINER HOHN", foundEmployees[1].GetValue<String>("NameUpper"));
			Assert.AreEqual("dr. rainer hohn", foundEmployees[1].GetValue<String>("NameLower"));
		}

		/// <summary>
		/// This test trims the substring 'Sio ' pf the first Employee to 'Sio'.
		/// </summary>
		[TestMethod]
		[Description("This test trims the substring 'Sio ' pf the first Employee to 'Sio'.")]
		public void String_09_Trim() {
			IQueryable<string> employeesQuery = from e in m_companyExampleContext.Employees
												select e.Name.Substring(0, 4).Trim();

			string foundEmployee = employeesQuery.First();

			Assert.AreEqual("Sio", foundEmployee);
		}

		#endregion

		#region Conversion Operators

		/// <summary>
		/// This sample uses ToDictionary to immediately evaluate a query and
		/// a key expression into an Dictionary".
		/// </summary>
		[TestMethod]
		[Description(
			"This sample uses ToDictionary to immediately evaluate a query and " + "a key expression into an Dictionary<K, T>.")]
		public void ToDictionary_01() {
			IQueryable<Employee> employeesQuery = from e in m_companyExampleContext.Employees select e;

			Dictionary<int, Employee> foundEmployees = employeesQuery.ToDictionary(e => e.Id);

			Assert.AreEqual(13, foundEmployees.Count);
			Assert.AreEqual("Sio Wernli", foundEmployees[1].Name);
			Assert.AreEqual("Dr. Rainer Hohn", foundEmployees[2].Name);
		}

		#endregion

		[TestInitialize]
		[DeploymentItem("TestSampleApplication.RequestHandler.Client.Internal.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Client.Application.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Server.Internal.xaml")]
		[DeploymentItem("TestSampleApplication.RequestHandler.Server.Application.xaml")]
		public void BeginTest() {
			//create a object query handler based on our data container
			var queryHandler = new ObjectQueryHandler(new ObjectBasedDataSource(CreateData()));

			m_companyExampleContext = new CompanyContext(queryHandler);

			//create the server
			m_server = InterLinqServer.GetSebarfServerForInterLinq(queryHandler, queryHandler,
																	"TestSampleApplication.RequestHandler.Server.Internal.xaml",
																	"TestSampleApplication.RequestHandler.Server.Application.xaml",
																	"net.tcp://localhost:9876/InterLinqService");
			m_server.Start();

			// create the interlinq client and connect to the server
			IClient client;
			ClientContext ctx;
			IServiceLocatorService serviceLocator;

			InterLinqClientFactory.CreateSebarfClientForInterlinq("TestSampleApplication.RequestHandler.Client.Internal.xaml",
																   "CachelessProfile_Server.xaml", "CachelessProfile.xaml",
																   "Client with id:" + Guid.NewGuid(),
																   "net.tcp://localhost:9876/InterLinqService", out client,
																   out ctx, out serviceLocator);

			m_client = client;
			m_client.Connect();
			m_companyExampleContext = new CompanyContext(ctx.QueryHandler);
		}

		[TestCleanup]
		public void EndTest() {
			m_server.Stop();
		}

		#region Private Methods

		private Dictionary<Type, IList> CreateData() {
			// Company Instant-Guezli
			var toReturn = new Dictionary<Type, IList>();
			var companies = new List<Company>();
			var employees = new List<Employee>();
			var departments = new List<Department>();
			toReturn.Add(typeof(Company), companies);
			toReturn.Add(typeof(Employee), employees);
			toReturn.Add(typeof(Department), departments);
			var cInstantGuezli = new Company();
			companies.Add(cInstantGuezli);
			cInstantGuezli.Name = "Instant-Guezli";
			cInstantGuezli.Foundation = new DateTime(1900, 01, 01);
			cInstantGuezli.ChiefExecutiveOfficer = new Employee();
			cInstantGuezli.ChiefExecutiveOfficer.Name = "Sio Wernli";
			cInstantGuezli.ChiefExecutiveOfficer.IsMale = true;
			cInstantGuezli.ChiefExecutiveOfficer.Salary = 20000.00d;
			cInstantGuezli.ChiefExecutiveOfficer.Grade = 10;
			employees.Add(cInstantGuezli.ChiefExecutiveOfficer);
			// Departments (3)
			cInstantGuezli.Departments.Add(new Department());
			cInstantGuezli.Departments.Add(new Department());
			cInstantGuezli.Departments.Add(new Department());
			departments.AddRange(cInstantGuezli.Departments);

			#region Department 1

			// General
			cInstantGuezli.Departments[0].Foundation = new DateTime(1910, 01, 01);
			cInstantGuezli.Departments[0].Name = "Instant-Guezli Research";
			cInstantGuezli.Departments[0].QualityLevel = 7;
			cInstantGuezli.Departments[0].Company = cInstantGuezli;
			// Manager
			cInstantGuezli.Departments[0].Manager = new Employee();
			cInstantGuezli.Departments[0].Manager.Name = "Dr. Rainer Hohn";
			cInstantGuezli.Departments[0].Manager.IsMale = true;
			cInstantGuezli.Departments[0].Manager.Salary = 10000.00d;
			cInstantGuezli.Departments[0].Manager.Grade = 9;
			cInstantGuezli.Departments[0].Manager.Department = cInstantGuezli.Departments[0];
			employees.Add(cInstantGuezli.Departments[0].Manager);
			// Employees
			cInstantGuezli.Departments[0].Employees.Add(new Employee());
			cInstantGuezli.Departments[0].Employees.Add(new Employee());
			cInstantGuezli.Departments[0].Employees.Add(new Employee());
			employees.AddRange(cInstantGuezli.Departments[0].Employees);
			// Employee 1
			cInstantGuezli.Departments[0].Employees[0].Name = "Stephanie Süss";
			cInstantGuezli.Departments[0].Employees[0].IsMale = false;
			cInstantGuezli.Departments[0].Employees[0].Salary = 5000.00d;
			cInstantGuezli.Departments[0].Employees[0].Grade = 6;
			cInstantGuezli.Departments[0].Employees[0].Department = cInstantGuezli.Departments[0];
			// Employee 2
			cInstantGuezli.Departments[0].Employees[1].Name = "Manuela Zucker";
			cInstantGuezli.Departments[0].Employees[1].IsMale = false;
			cInstantGuezli.Departments[0].Employees[1].Salary = 6000.00d;
			cInstantGuezli.Departments[0].Employees[1].Grade = 7;
			cInstantGuezli.Departments[0].Employees[1].Department = cInstantGuezli.Departments[0];
			// Employee 3
			cInstantGuezli.Departments[0].Employees[2].Name = "Harry Bo";
			cInstantGuezli.Departments[0].Employees[2].IsMale = true;
			cInstantGuezli.Departments[0].Employees[2].Salary = 4000.00d;
			cInstantGuezli.Departments[0].Employees[2].Grade = 4;
			cInstantGuezli.Departments[0].Employees[2].Department = cInstantGuezli.Departments[0];

			#endregion

			#region Department 2

			// General
			cInstantGuezli.Departments[1].Foundation = new DateTime(1900, 01, 01);
			cInstantGuezli.Departments[1].Name = "Instant-Guezli Production";
			cInstantGuezli.Departments[1].QualityLevel = 8;
			cInstantGuezli.Departments[1].Company = cInstantGuezli;
			// Manager
			cInstantGuezli.Departments[1].Manager = new Employee();
			cInstantGuezli.Departments[1].Manager.Name = "Prof. Joe Kolade";
			cInstantGuezli.Departments[1].Manager.IsMale = true;
			cInstantGuezli.Departments[1].Manager.Salary = 11000.00d;
			cInstantGuezli.Departments[1].Manager.Grade = 10;
			cInstantGuezli.Departments[1].Manager.Department = cInstantGuezli.Departments[1];
			employees.Add(cInstantGuezli.Departments[1].Manager);
			// Employees
			cInstantGuezli.Departments[1].Employees.Add(new Employee());
			cInstantGuezli.Departments[1].Employees.Add(new Employee());
			cInstantGuezli.Departments[1].Employees.Add(new Employee());
			employees.AddRange(cInstantGuezli.Departments[1].Employees);
			// Employee 1
			cInstantGuezli.Departments[1].Employees[0].Name = "Rainer Zufall";
			cInstantGuezli.Departments[1].Employees[0].IsMale = true;
			cInstantGuezli.Departments[1].Employees[0].Salary = 3000.00d;
			cInstantGuezli.Departments[1].Employees[0].Grade = 2;
			cInstantGuezli.Departments[1].Employees[0].Department = cInstantGuezli.Departments[1];
			// Employee 2
			cInstantGuezli.Departments[1].Employees[1].Name = "Clara Vorteil";
			cInstantGuezli.Departments[1].Employees[1].IsMale = false;
			cInstantGuezli.Departments[1].Employees[1].Salary = 6500.00d;
			cInstantGuezli.Departments[1].Employees[1].Grade = 5;
			cInstantGuezli.Departments[1].Employees[1].Department = cInstantGuezli.Departments[1];
			// Employee 3
			cInstantGuezli.Departments[1].Employees[2].Name = "Johannes Beer";
			cInstantGuezli.Departments[1].Employees[2].IsMale = true;
			cInstantGuezli.Departments[1].Employees[2].Salary = 5500.00d;
			cInstantGuezli.Departments[1].Employees[2].Grade = 6;
			cInstantGuezli.Departments[1].Employees[2].Department = cInstantGuezli.Departments[1];

			#endregion

			#region Department 3

			// General
			cInstantGuezli.Departments[2].Foundation = new DateTime(1980, 05, 05);
			cInstantGuezli.Departments[2].Name = "Instant-Guezli Import";
			cInstantGuezli.Departments[2].QualityLevel = 3;
			cInstantGuezli.Departments[2].Company = cInstantGuezli;
			// Manager
			cInstantGuezli.Departments[2].Manager = new Employee();
			cInstantGuezli.Departments[2].Manager.Name = "Anna Nass";
			cInstantGuezli.Departments[2].Manager.IsMale = false;
			cInstantGuezli.Departments[2].Manager.Salary = 12000.00d;
			cInstantGuezli.Departments[2].Manager.Grade = 8;
			cInstantGuezli.Departments[2].Manager.Department = cInstantGuezli.Departments[2];
			employees.Add(cInstantGuezli.Departments[2].Manager);
			// Employees
			cInstantGuezli.Departments[2].Employees.Add(new Employee());
			cInstantGuezli.Departments[2].Employees.Add(new Employee());
			cInstantGuezli.Departments[2].Employees.Add(new Employee());
			employees.AddRange(cInstantGuezli.Departments[2].Employees);
			// Employee 1
			cInstantGuezli.Departments[2].Employees[0].Name = "Lee Mone";
			cInstantGuezli.Departments[2].Employees[0].IsMale = true;
			cInstantGuezli.Departments[2].Employees[0].Salary = 3500.00d;
			cInstantGuezli.Departments[2].Employees[0].Grade = 1;
			cInstantGuezli.Departments[2].Employees[0].Department = cInstantGuezli.Departments[2];
			// Employee 2
			cInstantGuezli.Departments[2].Employees[1].Name = "Franziska Ner";
			cInstantGuezli.Departments[2].Employees[1].IsMale = false;
			cInstantGuezli.Departments[2].Employees[1].Salary = 5000.00d;
			cInstantGuezli.Departments[2].Employees[1].Grade = 6;
			cInstantGuezli.Departments[2].Employees[1].Department = cInstantGuezli.Departments[2];
			// Employee 3
			cInstantGuezli.Departments[2].Employees[2].Name = "Gertraut Sichnicht";
			cInstantGuezli.Departments[2].Employees[2].IsMale = false;
			cInstantGuezli.Departments[2].Employees[2].Salary = 4500.00d;
			cInstantGuezli.Departments[2].Employees[2].Grade = 5;
			cInstantGuezli.Departments[2].Employees[2].Department = cInstantGuezli.Departments[2];

			#endregion

			// Set the Id's
			for (int i = 0; i < companies.Count; i++) {
				companies[i].Id = i + 1;
			}
			for (int i = 0; i < departments.Count; i++) {
				departments[i].Id = i + 1;
			}
			for (int i = 0; i < employees.Count; i++) {
				employees[i].Id = i + 1;
			}
			return toReturn;
		}

		#endregion

		#region Private Fields

		private IClient m_client;
		private IServer m_server;

		#endregion
	}
}